
package com.aliyun.gts.gmall.manager.front.trade.controller;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URI;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.util.EntityUtils;

@Slf4j
public class ApiGwUtils {

    public static void main(String[] args) throws IOException {
        String ak = "1c25f48031b7bc89e1b25a149785ab38";
        String sk = "8b395eaa1da97f325ebf9021be5f72f0";
        String schema = "http";
        String method = "POST";
        String host = "101.37.255.88:8080";
        // 请求的api的路径
        String path = "/front-manager/api/login/sendSecurityCode";
        // String path = "/callback-integration/health";
        // 如果是post方法，http请求的body内容，
        // byte[] body = new byte[]{};
        byte[] body = "{\"phone\":\"18811119999\"}".getBytes();

        String bodyDigest = calcBodyDigest(body, sk);

        String urlSign = calcUrlHmacSignature(
                path,
                new HashMap<>(),
                method,
                ak, sk
        );
        Map<String, Header> headers = buildApiGwHeaders(host, urlSign, bodyDigest, ak);

        String url = schema + "://" + host + path;
        HttpUriRequest outRequest = RequestBuilder.create(method)
                .setUri(url)
                .setEntity(new InputStreamEntity(new ByteArrayInputStream(body), body.length))
                .build();
        outRequest.setHeaders(headers.values().toArray(new Header[0]));
        HttpClient httpClient = HttpClientBuilder.create().build();

        HttpResponse response = httpClient.execute(outRequest);

        log.info(JSON.toJSONString(EntityUtils.toString(response.getEntity())));
        // dosomethins with response
        if (httpClient != null && httpClient instanceof CloseableHttpClient) {
            ((CloseableHttpClient) httpClient).close();
        }
    }

    private static Map<String, Header> buildApiGwHeaders(String host, String urlSign, String bodyDigest, String ak) {
        Map<String, Header> headers = new HashMap();
        headers.put("accept", new BasicHeader("accept", "application/json"));
        headers.put("content-type", new BasicHeader("content-type", "application/json; charset=utf-8"));
        headers.put("X-HMAC-SIGNATURE", new BasicHeader("X-HMAC-SIGNATURE", urlSign));
        headers.put("X-HMAC-ACCESS-KEY", new BasicHeader("X-HMAC-ACCESS-KEY", ak));
        headers.put("X-HMAC-ALGORITHM", new BasicHeader("X-HMAC-ALGORITHM", "hmac-sha256"));
        headers.put("X-HMAC-DIGEST", new BasicHeader("X-HMAC-DIGEST", bodyDigest));
        return headers;
    }

    public static String calcUrlHmacSignature(String uri, Map<String, String> signedParams, String method, String accessKey,
                                              String secret) {
        try {
            Map<String, String> queries = signedParams;
            String[] sortedKeys = (String[]) signedParams.keySet().toArray(new String[0]);
            Arrays.sort(sortedKeys);
            StringBuilder canonicalizedQueryString = new StringBuilder();

            for (int i = 0; i < sortedKeys.length; ++i) {
                String key = sortedKeys[i];
                if (queries.get(key) != null && queries.get(key).length() > 0) {
                    canonicalizedQueryString.append("&").append(encode(key)).append("=").append(
                            encode((String) queries.get(key)));
                }
            }
            String canonicalizedString = "";
            //只有get请求对query进行加密处理，暂未开启body校验，所以post请求这里为空
            if (method.equals("GET")) {
                if (canonicalizedQueryString.toString().length() > 0) {
                    canonicalizedString = canonicalizedQueryString.substring(1);
                }
            }

            StringBuilder stringToSign = new StringBuilder();
            stringToSign.append(method);
            stringToSign.append("\n");
            stringToSign.append(uri);
            stringToSign.append("\n");
            stringToSign.append(canonicalizedString);
            stringToSign.append("\n");
            stringToSign.append(accessKey);
            stringToSign.append("");
            stringToSign.append("\n");
            stringToSign.append("\n");
            Mac mac = null;
            try {
                mac = Mac.getInstance("HmacSHA256");
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            //use sk
            assert mac != null;
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            //signString
            byte[] signData = mac.doFinal(stringToSign.toString().getBytes("UTF-8"));
            return Base64.encodeBase64String(signData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "null";
    }

    private static String getQueryString(Map<String, String> querys) {
        StringBuilder canonicalizedQueryString = new StringBuilder();
        for (Map.Entry<String, String> queryEntry : querys.entrySet()) {
            if (queryEntry.getKey() != null && queryEntry.getKey().length() > 0) {
                canonicalizedQueryString.append("&").append(encode(queryEntry.getKey())).append("=").append(
                        encode((String) queryEntry.getValue()));
            }
        }
        String canonicalizedString = "";
        if (canonicalizedQueryString.toString().length() > 0) {
            canonicalizedString = canonicalizedQueryString.substring(1);
        }
        return canonicalizedString;
    }

    private static byte[] readBody(HttpServletRequest inRequest) throws IOException {
        byte[] buffer;
        ServletInputStream inputStream = inRequest.getInputStream();
        int len = inRequest.getContentLength();
        if (len > 0) {
            buffer = IOUtils.toByteArray(inputStream);
        } else {
            buffer = new byte[0];
        }
        return buffer;
    }

    private static String calcBodyDigest(byte[] buffer, String secret) {
        try {
            Mac mac = null;
            try {
                mac = Mac.getInstance("HmacSHA256");
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            //use sk
            assert mac != null;
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            //signString
            byte[] signData = mac.doFinal(buffer);
            return Base64.encodeBase64String(signData);
        } catch (IOException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String encode(String value) {
        try {
            return URLEncoder.encode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

